package datetime

import (
	"fmt"
	"time"
)

// 时间格式
const (
	// YearMouthDay 年-月-日
	YearMouthDay = "2006-01-02"
	// YearMouth 年-月
	YearMouth = "2006-01"
	// MouthDay 月-日
	MouthDay = "01-02"
	// YearMouthDayHourMinute 年-月-日 时:分
	YearMouthDayHourMinute = "2006-01-02 15:04"
	// YearMouthDayHourMinuteSecond 年-月-日 时:分:秒
	YearMouthDayHourMinuteSecond = "2006-01-02 15:04:05"
	// DayHourMinute 日 时:分
	DayHourMinute = "02 15:04"
	// DayHourMinuteSecond 日 时:分:秒
	DayHourMinuteSecond = "02 15:04:05"
	// HourMinute 时:分
	HourMinute = "15:04"
	// HourMinuteSecond 时:分:秒
	HourMinuteSecond = "15:04:05"
	// MinuteSecond 分:秒
	MinuteSecond = "04:05"
)

// AddMinutes 增加分钟
// t:时间  minute:分钟
// 返回:增加后的时间
func AddMinutes(t time.Time, minute int64) time.Time {
	return t.Add(time.Minute * time.Duration(minute))
}

// AddHours 增加小时
// t:时间  hours:小时
// 返回:增加后的时间
func AddHours(t time.Time, hours int64) time.Time {
	return t.Add(time.Hour * time.Duration(hours))
}

// AddDays 增加天数
// t:时间  days:天数
// 返回:增加后的时间
func AddDays(t time.Time, days int64) time.Time {
	return t.Add(24 * time.Hour * time.Duration(days))
}

// IsLeapYear 是否闰年
// year:年份
// 返回:是否闰年
func IsLeapYear(year int) bool {
	return (year%4 == 0 && year%100 != 0) || year%400 == 0
}

// AddYears 增加年份
// t:时间  years:年数
// 返回:增加后的时间
func AddYears(t time.Time, years int64) time.Time {
	var yearDays int64
	if IsLeapYear(t.Year()) {
		yearDays = 366
	} else {
		yearDays = 365
	}
	return t.Add(time.Hour * 24 * time.Duration(yearDays*years))
}

// FormatYearMouthDay 格式化年-月-日
// t:时间
// 返回:年-月-日
func FormatYearMouthDay(t time.Time) string {
	return t.Format(YearMouthDay)
}

// FormatTime 格式化当前时间
// t:时间
// 返回:当前时间 时:分:秒
func FormatTime(t time.Time) string {
	return t.Format(HourMinuteSecond)
}

// FormatDateTime 格式化当前日期时间
// t:时间
// 返回:当前日期时间 年-月-日 时:分:秒
func FormatDateTime(t time.Time) string {
	return t.Format(YearMouthDayHourMinuteSecond)
}

// FormatStartTime 格式化当前日期的开始时间
// t:时间
// 返回:当前日期的开始时间 年-月-日 00:00:00
func FormatStartTime(t time.Time) string {
	return fmt.Sprintf("%s 00:00:00", FormatYearMouthDay(t))
}

// FormatEndTime 格式化当前日期的结束时间
// t:时间
// 返回:当前日期的结束时间 年-月-日 23:59:59
func FormatEndTime(t time.Time) string {
	return fmt.Sprintf("%s 23:59:59", FormatYearMouthDay(t))
}

// FormatStartTimestamp 格式化当前日期的开始时间戳
// t:时间
// 返回:当前日期的开始时间戳
func FormatStartTimestamp(t time.Time) int64 {
	ts := FormatStartTime(t)
	tp, _ := time.Parse(YearMouthDayHourMinuteSecond, ts)
	return tp.UTC().Unix() - 8*3600
}

// FormatEndTimestamp 格式化当前日期的结束时间戳
// t:时间
// 返回:当前日期的结束时间戳
func FormatEndTimestamp(t time.Time) int64 {
	ts := FormatEndTime(t)
	tp, _ := time.Parse(YearMouthDayHourMinuteSecond, ts)
	return tp.UTC().Unix() - 8*3600
}

// GetNowTimestamp 获取当前时间戳
// 返回:当前时间戳
func GetNowTimestamp() int64 {
	return time.Now().Unix()
}

// StartOfMinute 获取当前分钟开始时间
// t:时间
// 返回:当前分钟开始时间
func StartOfMinute(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
}

// EndOfMinute 获取当前分钟结束时间
// t:时间
// 返回:当前分钟结束时间
func EndOfMinute(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
}

// StartOfHour 获取当前小时开始时间
// t:时间
// 返回:当前小时开始时间
func StartOfHour(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
}

// EndOfHour 获取当前小时结束时间
// t:时间
// 返回:当前小时结束时间
func EndOfHour(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
}

// StartOfDay 获取当前天开始时间
// t:时间
// 返回:当前天开始时间
func StartOfDay(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}

// EndOfDay 获取当前天结束时间
// t:时间
// 返回:当前天结束时间
func EndOfDay(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}

// StartOfWeek 获取当前周开始时间
// t:时间
// startFrom:开始星期几，默认是星期六
// 返回:当前周开始时间
func StartOfWeek(t time.Time, startFrom ...time.Weekday) time.Time {
	var startWithWeekDay = time.Saturday
	if len(startFrom) > 0 {
		startWithWeekDay = startFrom[0]
	}
	y, m, d := t.AddDate(0, 0, int(startWithWeekDay-t.Weekday())).Date()
	startWithWeek := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
	if startWithWeek.After(t) {
		return startWithWeek.AddDate(0, 0, -7)
	}
	return startWithWeek
}

// EndOfWeek 获取当前周结束时间
// t:时间
// endWith:结束星期几，默认是星期六
// 返回:当前周结束时间
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
	var endWithWeekday = time.Saturday
	if len(endWith) > 0 {
		endWithWeekday = endWith[0]
	}
	y, m, d := t.AddDate(0, 0, int(endWithWeekday-t.Weekday())).Date()
	var endWithWeek = time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
	if endWithWeek.Before(t) {
		endWithWeek = endWithWeek.AddDate(0, 0, 7)
	}
	return endWithWeek
}

// DifferenceSeconds 获取时间差
// t:时间1 t2:时间2
// 返回:时间差 单位秒
func DifferenceSeconds(t time.Time, t2 time.Time) int64 {
	return t2.Unix() - t.Unix()
}

// IsWeekEnd 判断是否是周末
// t:时间
// 返回:是否是周末
func IsWeekEnd(t time.Time) bool {
	return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
}

// ToTimestamp 将时间转换为时间戳, 按照时区 timezone 进行转换
// t:时间
// timezone:时区，默认是 UTC
// 返回:时间戳
func ToTimestamp(t time.Time, timezone ...string) int64 {
	if timezone == nil || len(timezone) == 0 {
		return t.Unix()
	}
	loc, err := time.LoadLocation(timezone[0])
	if err != nil {
		return t.Unix()
	}
	return t.In(loc).Unix()
}

// DifferenceDays 计算两个日期相差的天数
// start:开始时间 end:结束时间
// 返回:相差的天数
func DifferenceDays(start, end time.Time) int {
	duration := end.Sub(start)
	days := int(duration.Hours() / 24)
	return days
}

// MinTime 获取时间列表中最小的时间
// t1:时间 t:时间列表
// 返回:最小的时间
func MinTime(t1 time.Time, timeList ...time.Time) time.Time {
	minTime := t1
	for _, t := range timeList {
		if t.Before(minTime) {
			minTime = t
		}
	}
	return minTime
}

// MaxTime 获取时间列表中最大的时间
// t1:时间 t:时间列表
// 返回:最大的时间
func MaxTime(t1 time.Time, timeList ...time.Time) time.Time {
	maxTime := t1
	for _, t := range timeList {
		if t.After(maxTime) {
			maxTime = t
		}
	}
	return maxTime
}

// MaxAndMin 获取时间列表中最大和最小时间
// t1:时间 t:时间列表
// 返回:最大和最小时间
func MaxAndMin(t1 time.Time, timeList ...time.Time) (maxTime, minTime time.Time) {
	maxTime = t1
	minTime = t1
	for _, t := range timeList {
		if t.After(maxTime) {
			maxTime = t
		}
		if t.Before(minTime) {
			minTime = t
		}
	}
	return maxTime, minTime
}
